package com.newtouch.bxzs.account.service;

import com.newtouch.bxzs.account.model.ClaimSet;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.KeyUse;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.util.Date;
import java.util.Objects;

/**
 * JWK工具类
 *
 * <p>
 * <b>History:</b>
 * <table border="1">
 * <tr>
 * <th>Date</th>
 * <th>Operator</th>
 * <th>Memo</th>
 * </tr>
 * <tr>
 * <td>2021年3月4日</td>
 * <td>Amour</td>
 * <td>Create</td>
 * </tr>
 * </table>
 * 
 * @author Amour
 *  
 * @version 1.0.0
 * @since 1.0.0
 */
@Component
public class JwtGenerator {

	private RSAKey rsaKey;

	public JwtGenerator(@Value("${jwk-json}") String json) throws ParseException {
		final JWK jwk = JWK.parse(json);
		this.rsaKey = jwk.toRSAKey();
	}

	@SneakyThrows
	public JWKSet getJWKSet() {
		RSAKey.Builder builder = new RSAKey.Builder(rsaKey.toRSAPublicKey()).keyUse(KeyUse.SIGNATURE)
				.algorithm(JWSAlgorithm.RS256).keyID("123");
		return new JWKSet(builder.build());
	}

	@SneakyThrows
	public JWKSet getJWKSetSimple() {
		return new JWKSet(rsaKey.toPublicJWK());
	}

	public String generateJwtToken(ClaimSet claimSet) throws JOSEException {
		Objects.requireNonNull(claimSet, "请创建声明集合对象ClaimSet");
		final JWTClaimsSet.Builder claimsBuilder = new JWTClaimsSet.Builder().subject(claimSet.getUserName())
				.issuer(claimSet.getIssuer())
				.expirationTime(new Date(System.currentTimeMillis() + 60_000 * 12 * claimSet.getKeepMinutes()));

		claimsBuilder.claim("userId", claimSet.getUserId());
		claimsBuilder.claim("userJobNumber", claimSet.getUserJobNumber());
		claimsBuilder.claim("userLoginAccountNumber", claimSet.getUserLoginAccountNumber());
		claimsBuilder.claim("userName", claimSet.getUserName());
		claimsBuilder.claim("userCertificateType", claimSet.getUserCertificateType());
		claimsBuilder.claim("userCertificateNumber", claimSet.getUserCertificateNumber());
		claimsBuilder.claim("userOrganizationCode", claimSet.getUserOrganizationCode());
		claimsBuilder.claim("userOrganizationName", claimSet.getUserOrganizationName());
		claimsBuilder.claim("userPhone", claimSet.getUserPhone());

		JWSSigner signer = new RSASSASigner(rsaKey);

		SignedJWT signedJWT = new SignedJWT(
				// new
				// JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JWT).keyID(rsaKey.getKeyID()).build(),
				new JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JWT).build(), claimsBuilder.build());

		signedJWT.sign(signer);
		return signedJWT.serialize();
	}

	@SneakyThrows
	public boolean isValid(String token) {
		RSASSAVerifier rsassaVerifier = new RSASSAVerifier(rsaKey.toRSAPublicKey());
		SignedJWT jwt = SignedJWT.parse(token);
		return jwt.verify(rsassaVerifier);
	}
}
